#什么是高阶函数和闭包举例说明
#高阶函数
import datetime


def fn(): #定义一个普通函数
    return
def hfn(func): #定义一个高阶函数
    return func

hfn(fn) #将一个函数对象作为参数传递给另一个函数，或者一个函数返回值为另一个函数，这个就是高阶函数

#闭包
def outer():
    test = 1 #自由变量
    def inner():
        return test #内层函数用到了外层函数的自由变量，就产生了闭包
    return inner
f = outer()
print(f())
# functools
from functools import reduce,partial,wraps,lru_cache
fn = reduce(lambda x,y:x*y,range(1,6)) #求5的阶乘，第一个参数为函数，这个函数的返回值为下一次迭代时x的值，range逐个迭代出来每次赋值给y
print(fn)

def add(x,y,z):
    return x + y + z
#partial对原函数封装，将参数x固定下来，添加了固定的默认值，newadd只需要传参y，z
newadd = partial(add,x=1)
# print(newadd(3,z=2))#传参y需要指明，不能用位置传参，否则x会multiple values
print(newadd(y=1,z=1))#正确
import inspect
print(inspect.signature(newadd))#(*, x=1, y, z)

def logger(fn):
    @wraps(fn)
    def wrapper(*args,**kwargs):
        '''
        wrapper
        :param args:
        :param kwargs:
        :return: fn
        '''
        ret = fn(*args,**kwargs)
        return ret
    return wrapper
@logger
def sub(x,y):
    '''
    sub
    :param x:
    :param y:
    :return: x-y
    '''
    return x - y

print(sub.__doc__,"\n",sub.__name__)
'''
54行输出如下，有wraps效果
    sub
    :param x:
    :param y:
    :return: x-y
     
 sub
'''

'''
54行输出如下，没有wraps效果
wrapper
        :param args:
        :param kwargs:
        :return: fn
         
 wrapper
 
wraps可以将被装饰函数的__doc__,__name__等属性赋予装饰函数wrapper，实现较完整的偷梁换柱
'''
@lru_cache()
# 如果没有lru_cache,计算fib(40)需要
# 2024-08-01 15:20:30.568000
# 102334155
# 2024-08-01 15:20:35.347015
# 如果有lru_cache,计算fib(40)需要，几乎不消耗什么时间
# 2024-08-01 15:22:11.395624
# 102334155
# 2024-08-01 15:22:11.395624
# lru_cache()函数接收两个参数maxsize，typed，可以定义缓存的大小和不同类型的函数参数是否单独缓存，它可以形成函数参数和返回值之间的映射存储，
# 下次计算时就可以复用这个缓存
def fib(n):
    return 1 if n < 3 else fib(n-1)+fib(n-2)
print(datetime.datetime.now())
print(fib(40))
print(datetime.datetime.now())
'''
类型注解就是注解的作用，弥补动态强类型python不约束变量类型产生的弊端，写代码时可以加上注解，IDE可以更好的推断方法，提示可能的隐患，提高编程效率
'''